package os.kernelProcess;

import java.util.Enumeration;
import java.util.Hashtable;

import os.MiniProcess;
import os.MiniThread;
import os.kernelProcess.queues.MiniQueue;

/**
 * Super class of all scheduling schemes. You should extend it to implement any
 * of the scheduling schemes like Round-Robin.
 * 
 * @author Ahmed El-Eryan
 * 
 */
public abstract class SchedulerThread extends MiniThread {

	/**
	 * Constructor of MiniScheduler.
	 * 
	 * @param process
	 *            KernelProcess.
	 * @param tid
	 *            id of the scheduler thread.
	 */
	protected int quantum;

	public SchedulerThread(MiniProcess process, String tid, int quantum)
	{
		super(process, tid);
		quantum = 0;
		// description shown in the ProcessMonitor tab.
		description = "Scheduler Thread";
	}
	public SchedulerThread(MiniProcess process, String tid)
	{
		super(process, tid);
		quantum = 0;
		// description shown in the ProcessMonitor tab.
		description = "Scheduler Thread";
	}
	/**
	 * Contains threads contending for a processor.
	 */
	protected MiniQueue readyQueue;

	/**
	 * Contains threads blocked because of an IO operation.
	 */
	protected Hashtable<String, MiniThread> blockedQueue;

	/**
	 * Contains threads suspended by the user.
	 */
	protected Hashtable<String, MiniThread> suspendedQueue;

	/**
	 * Current running thread.
	 */
	protected MiniThread runningThread;

	/**
	 * Run method of the scheduler thread just invokes the <b>
	 * {@link #schedule()}</b> method.
	 */
	@Override
	public void run() {
		schedule();
	}

	/**
	 * <b>UnImplemented</b>: Invoked to add a thread to the scheduling.
	 * 
	 * @param thread
	 *            Thread to be added.
	 */
	// tested
	public void addThread(MiniThread thread) {
		// XXX: Done MiniScheduler::addThread()
		System.err.println("Thread added before");
		readyQueue.append(thread);
		
		thread.setThreadState(THREAD_READY);
		System.err.println("Thread added after");
	}

	/**
	 * Invoked when the user chooses to resume the given process.
	 * 
	 * @param process
	 *            Process to resume.
	 */
	// XXX not tested
	public void resumeProcess(MiniProcess process) {
		process.setSuspended(false);
		Hashtable<String, MiniThread> threads = process.getThreads();
		Enumeration<MiniThread> e = threads.elements();
		while (e.hasMoreElements()) {
			resumeThread(e.nextElement());
		}
	}

	/**
	 * Invoked when the user chooses to suspend the given process.
	 * 
	 * @param process
	 *            Process to suspend.
	 */
	// tested
	public void suspendProcess(MiniProcess process) {
		process.setSuspended(true);
		Hashtable<String, MiniThread> threads = process.getThreads();
		Enumeration<MiniThread> e = threads.elements();
		while (e.hasMoreElements()) {
			suspendThread(e.nextElement());
		}
	}

	/**
	 * Invoked when the user chooses to terminate either the given thread or the
	 * process to which this thread belongs. Note that in this case the thread
	 * is forced to terminate by the user.
	 * 
	 * @param thread
	 *            Thread to be terminated.
	 */
	public abstract void threadTerminated();

	/**
	 * Invoked when the user chooses to terminate the given process.
	 * 
	 * @param process
	 *            Process to be terminated.
	 */

	public abstract void terminateProcess(MiniProcess process);

	/**
	 * <b>UnImplemented</b>: Invoked to indicate that the <b>running thread</b>
	 * terminates its code. Note that it should be called when the thread
	 * terminates on its own.
	 */
	public abstract void terminateThread(MiniThread thread);

	/**
	 * <b>UnImplemented</b>: Invoked when the thread requests and IO operation.
	 * The thread is blocked until the completion of the IO operation.
	 */
	public abstract void blockThread();

	/**
	 * <b>UnImplemented</b>: Invoked when an IO operation is completed for the
	 * given thread. The thread should be unblocked.
	 * 
	 * @param thread
	 *            Thread to unblock.
	 */
	public abstract void unblockThread(MiniThread thread);

	/**
	 * <b>UnImplemented</b>: Invoked when the user chooses to suspend either the
	 * given thread or the process to which this thread belongs.
	 * 
	 * @param thread
	 *            Thread to suspend.
	 */

	public abstract void suspendThread(MiniThread thread);

	/**
	 * <b>UnImplemented</b>: Invoked when the user chooses to resume either the
	 * given thread or the process to which this thread belongs. Note that the
	 * thread should be suspended first in order to be resumed!
	 * 
	 * @param thread
	 *            Thread to resume.
	 */

	public abstract void resumeThread(MiniThread thread);

	public abstract void schedule();
	
	public abstract void threadStopped(MiniThread thread);

	public abstract String getSchedulerName();

	public int getQuantum()
	{
		return quantum;
	}

}
